package websocket

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

// Client WebSocket客户端
type Client struct {
	ID       string          // 客户端唯一ID（通常是用户ID）
	UserID   uint            // 用户ID
	Username string          // 用户名
	Conn     *websocket.Conn // WebSocket连接
	Send     chan []byte     // 发送消息通道
	Manager  *Manager        // 管理器引用
}

// Manager WebSocket连接管理器
type Manager struct {
	clients     map[string]*Client     // 所有连接的客户端 map[clientID]*Client
	userClients map[uint][]*Client     // 用户ID到客户端列表的映射 map[userID][]*Client
	register    chan *Client           // 注册客户端通道
	unregister  chan *Client           // 注销客户端通道
	broadcast   chan *BroadcastMessage // 广播消息通道
	mu          sync.RWMutex           // 读写锁
}

// BroadcastMessage 广播消息
type BroadcastMessage struct {
	TargetUserIDs []uint // 目标用户ID列表（为空则广播给所有人）
	Message       []byte // 消息内容
}

// 连接限制常量
const (
	MaxConnectionsPerUser = 3     // 单用户最大连接数
	MaxTotalConnections   = 10000 // 系统最大总连接数
)

var (
	// 全局管理器实例
	globalManager *Manager
	once          sync.Once
)

// GetUpgrader 获取WebSocket升级器
func GetUpgrader() websocket.Upgrader {
	return websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		// 跨域安全检查
		CheckOrigin: func(r *http.Request) bool {
			origin := r.Header.Get("Origin")

			// 允许的域名列表（生产环境请修改为实际域名）
			allowedOrigins := []string{
				"http://localhost:3000", // 开发环境 - 前端
				"http://localhost:8080", // 开发环境 - 后端
				"http://127.0.0.1:3000",
				"http://127.0.0.1:8080",
				// 生产环境域名（请根据实际情况修改）
				// "https://yourdomain.com",
				// "https://app.yourdomain.com",
				// "https://admin.yourdomain.com",
			}

			// 检查是否在允许列表中
			for _, allowed := range allowedOrigins {
				if origin == allowed {
					return true
				}
			}

			// 拒绝未授权的域名
			log.Printf("[安全警告] 拒绝来自 %s 的 WebSocket 连接请求", origin)
			return false
		},
	}
}

// GetManager 获取全局WebSocket管理器实例（单例模式）
func GetManager() *Manager {
	once.Do(func() {
		globalManager = &Manager{
			clients:     make(map[string]*Client),
			userClients: make(map[uint][]*Client),
			register:    make(chan *Client),
			unregister:  make(chan *Client),
			broadcast:   make(chan *BroadcastMessage, 256),
		}
		go globalManager.Run()
	})
	return globalManager
}

// Run 运行WebSocket管理器
func (m *Manager) Run() {
	for {
		select {
		case client := <-m.register:
			m.mu.Lock()

			// 检查系统总连接数限制
			if len(m.clients) >= MaxTotalConnections {
				m.mu.Unlock()
				client.Conn.Close()
				log.Printf("[限流] 系统连接数已达上限 %d，拒绝用户 %d 的连接", MaxTotalConnections, client.UserID)
				continue
			}

			// 检查单用户连接数
			userConns := m.userClients[client.UserID]
			if len(userConns) >= MaxConnectionsPerUser {
				// 关闭该用户最旧的连接
				m.closeOldestUserConnection(client.UserID)
				log.Printf("[限流] 用户 %d 连接数超限，已关闭最旧连接", client.UserID)
			}

			// 添加到 clients map
			m.clients[client.ID] = client
			// 添加到 userClients map
			m.userClients[client.UserID] = append(m.userClients[client.UserID], client)

			m.mu.Unlock()
			log.Printf("[WebSocket] 用户 %s (ID:%d) 已连接，当前在线: %d 人 (%d 个连接)",
				client.Username, client.UserID, len(m.userClients), len(m.clients))

		case client := <-m.unregister:
			m.mu.Lock()
			if _, ok := m.clients[client.ID]; ok {
				delete(m.clients, client.ID)
				close(client.Send)

				// 从 userClients 中移除
				userConns := m.userClients[client.UserID]
				for i, c := range userConns {
					if c.ID == client.ID {
						m.userClients[client.UserID] = append(userConns[:i], userConns[i+1:]...)
						break
					}
				}
				// 如果用户没有其他连接了，删除该用户记录
				if len(m.userClients[client.UserID]) == 0 {
					delete(m.userClients, client.UserID)
				}

				log.Printf("[WebSocket] 用户 %s (ID:%d) 已断开，当前在线: %d 人 (%d 个连接)",
					client.Username, client.UserID, len(m.userClients), len(m.clients))
			}
			m.mu.Unlock()

		case broadcastMsg := <-m.broadcast:
			m.mu.RLock()
			if len(broadcastMsg.TargetUserIDs) == 0 {
				// 广播给所有人
				for _, client := range m.clients {
					select {
					case client.Send <- broadcastMsg.Message:
					default:
						// 发送失败，关闭连接
						close(client.Send)
						delete(m.clients, client.ID)
					}
				}
			} else {
				// 发送给指定用户（可能有多个连接）
				for _, userID := range broadcastMsg.TargetUserIDs {
					if clients, ok := m.userClients[userID]; ok {
						for _, client := range clients {
							select {
							case client.Send <- broadcastMsg.Message:
							default:
								// 发送失败，关闭连接
								close(client.Send)
								delete(m.clients, client.ID)
							}
						}
					}
				}
			}
			m.mu.RUnlock()
		}
	}
}

// Register 注册客户端
func (m *Manager) Register(client *Client) {
	m.register <- client
}

// Unregister 注销客户端
func (m *Manager) Unregister(client *Client) {
	m.unregister <- client
}

// SendToUser 发送消息给指定用户
func (m *Manager) SendToUser(userID uint, message interface{}) error {
	data, err := json.Marshal(message)
	if err != nil {
		return err
	}

	m.broadcast <- &BroadcastMessage{
		TargetUserIDs: []uint{userID},
		Message:       data,
	}
	return nil
}

// SendToUsers 发送消息给多个用户
func (m *Manager) SendToUsers(userIDs []uint, message interface{}) error {
	data, err := json.Marshal(message)
	if err != nil {
		return err
	}

	m.broadcast <- &BroadcastMessage{
		TargetUserIDs: userIDs,
		Message:       data,
	}
	return nil
}

// BroadcastToAll 广播消息给所有在线用户
func (m *Manager) BroadcastToAll(message interface{}) error {
	data, err := json.Marshal(message)
	if err != nil {
		return err
	}

	m.broadcast <- &BroadcastMessage{
		TargetUserIDs: nil, // nil表示广播给所有人
		Message:       data,
	}
	return nil
}

// IsUserOnline 检查用户是否在线
func (m *Manager) IsUserOnline(userID uint) bool {
	m.mu.RLock()
	defer m.mu.RUnlock()
	clients, ok := m.userClients[userID]
	return ok && len(clients) > 0
}

// GetOnlineUserIDs 获取所有在线用户ID（去重）
func (m *Manager) GetOnlineUserIDs() []uint {
	m.mu.RLock()
	defer m.mu.RUnlock()

	userIDs := make([]uint, 0, len(m.userClients))
	for userID := range m.userClients {
		userIDs = append(userIDs, userID)
	}
	return userIDs
}

// GetOnlineCount 获取在线用户数量（去重）
func (m *Manager) GetOnlineCount() int {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return len(m.userClients)
}

// GetTotalConnectionCount 获取总连接数（包含同一用户的多个连接）
func (m *Manager) GetTotalConnectionCount() int {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return len(m.clients)
}

// getUserClientID 生成用户的客户端ID（带时间戳确保唯一）
func (m *Manager) getUserClientID(userID uint) string {
	return fmt.Sprintf("user_%d_%d", userID, time.Now().UnixNano())
}

// closeOldestUserConnection 关闭用户最旧的连接
func (m *Manager) closeOldestUserConnection(userID uint) {
	clients := m.userClients[userID]
	if len(clients) == 0 {
		return
	}

	// 第一个连接是最旧的（因为是按时间顺序添加的）
	oldestClient := clients[0]

	if oldestClient != nil {
		// 发送强制下线通知
		forceLogout := map[string]interface{}{
			"type":    "FORCE_LOGOUT",
			"reason":  "新设备登录",
			"message": "您的账号在其他设备登录，当前连接已断开",
		}
		if data, err := json.Marshal(forceLogout); err == nil {
			select {
			case oldestClient.Send <- data:
				time.Sleep(100 * time.Millisecond) // 等待消息发送
			default:
			}
		}

		// 关闭连接
		close(oldestClient.Send)
		oldestClient.Conn.Close()
		delete(m.clients, oldestClient.ID)
	}
}

// ReadPump 读取客户端消息
func (c *Client) ReadPump() {
	defer func() {
		c.Manager.Unregister(c)
		c.Conn.Close()
	}()

	// 设置读取超时
	c.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
	c.Conn.SetPongHandler(func(string) error {
		c.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
		return nil
	})

	for {
		_, message, err := c.Conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("[WebSocket] 读取错误: %v", err)
			}
			break
		}

		// 处理客户端发来的消息
		// 尝试解析为 JSON 格式
		var msg map[string]interface{}
		if err := json.Unmarshal(message, &msg); err == nil {
			// 处理业务层心跳
			if msgType, ok := msg["type"].(string); ok && msgType == "PING" {
				// 响应 PONG
				pongMsg := map[string]interface{}{
					"type":      "PONG",
					"timestamp": time.Now(),
				}
				if data, err := json.Marshal(pongMsg); err == nil {
					select {
					case c.Send <- data:
						log.Printf("[WebSocket] 响应心跳 PONG 给用户 %d", c.UserID)
					default:
						log.Printf("[WebSocket] 发送 PONG 失败，通道已满")
					}
				}
				continue
			}
		}

		// 其他消息记录日志（主要通过REST API处理）
		log.Printf("[WebSocket] 收到来自用户 %d 的消息: %s", c.UserID, string(message))
	}
}

// WritePump 向客户端发送消息
func (c *Client) WritePump() {
	ticker := time.NewTicker(54 * time.Second) // 心跳定时器
	defer func() {
		ticker.Stop()
		c.Conn.Close()
	}()

	for {
		select {
		case message, ok := <-c.Send:
			c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if !ok {
				// 管理器关闭了通道
				c.Conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			w, err := c.Conn.NextWriter(websocket.TextMessage)
			if err != nil {
				return
			}
			w.Write(message)

			// 将通道中的其他消息一起发送
			n := len(c.Send)
			for i := 0; i < n; i++ {
				w.Write([]byte{'\n'})
				w.Write(<-c.Send)
			}

			if err := w.Close(); err != nil {
				return
			}

		case <-ticker.C:
			// 发送心跳ping
			c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if err := c.Conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		}
	}
}
